Java/Network Protocol/Modem
Содержание
A tiny version of Ward Christensen"s MODEM program for UNIX
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; /**
* a tiny version of Ward Christensen"s MODEM program for UNIX. * Written ~ 1980 by Andrew Scott Beals. Last revised 1982. * A.D. 2000 - dragged from the archives for use in Java Cookbook. * * @author C version by Andrew Scott Beals, sjobrg.andy%mit-oz@mit-mc.arpa. * @author Java version by Ian F. Darwin, http://www.darwinsys.ru/ * $Id: TModem.java,v 1.10 2004/04/11 23:50:40 ian Exp $ */
public class TModem {
protected final byte CPMEOF = 26; /* control/z */ protected final int MAXERRORS = 10; /* max times to retry one block */ protected final int SECSIZE = 128; /* cpm sector, transmission block */ protected final int SENTIMOUT = 30; /* timeout time in send */ protected final int SLEEP = 30; /* timeout time in recv */ /* Protocol characters used */ protected final byte SOH = 1; /* Start Of Header */ protected final byte EOT = 4; /* End Of Transmission */ protected final byte ACK = 6; /* ACKnowlege */ protected final byte NAK = 0x15; /* Negative AcKnowlege */ protected InputStream inStream; protected OutputStream outStream; protected PrintWriter errStream; /** Construct a TModem */ public TModem(InputStream is, OutputStream os, PrintWriter errs) { inStream = is; outStream = os; errStream = errs; } /** Construct a TModem with default files (stdin and stdout). */ public TModem() { inStream = System.in; outStream = System.out; errStream = new PrintWriter(System.err); } /** A main program, for direct invocation. */ public static void main(String[] argv) throws IOException, InterruptedException { /* argc must == 2, i.e., `java TModem -s filename" */ if (argv.length != 2) usage(); if (argv[0].charAt(0) != "-") usage(); TModem tm = new TModem(); tm.setStandalone(true); boolean OK = false; switch (argv[0].charAt(1)){ case "r": OK = tm.receive(argv[1]); break; case "s": OK = tm.send(argv[1]); break; default: usage(); } System.out.print(OK?"Done OK":"Failed"); System.exit(0); } /* give user minimal usage message */ protected static void usage() { System.err.println("usage: TModem -r/-s file"); // not errStream, not die(), since this is static. System.exit(1); } /** If we"re in a standalone app it is OK to System.exit() */ protected boolean standalone = false; public void setStandalone(boolean is) { standalone = is; } public boolean isStandalone() { return standalone; } /** A flag used to communicate with inner class IOTimer */ protected boolean gotChar; /** An inner class to provide a read timeout for alarms. */ class IOTimer extends Thread { String message; long milliseconds; /** Construct an IO Timer */ IOTimer(long sec, String mesg) { milliseconds = 1000 * sec; message = mesg; } public void run() { try { Thread.sleep(milliseconds); } catch (InterruptedException e) { // can"t happen } /** Implement the timer */ if (!gotChar) errStream.println("Timed out waiting for " + message); try { die(1); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } /* * send a file to the remote */ public boolean send(String tfile) throws IOException, InterruptedException { char checksum, index, blocknumber, errorcount; byte character; byte[] sector = new byte[SECSIZE]; int nbytes; DataInputStream foo; foo = new DataInputStream(new FileInputStream(tfile)); errStream.println( "file open, ready to send"); errorcount = 0; blocknumber = 1; // The C version uses "alarm()", a UNIX-only system call, // to detect if the read times out. Here we do detect it // by using a Thread, the IOTimer class defined above. gotChar = false; new IOTimer(SENTIMOUT, "NAK to start send").start(); do { character = getchar(); gotChar = true; if (character != NAK && errorcount < MAXERRORS) ++errorcount; } while (character != NAK && errorcount < MAXERRORS); errStream.println( "transmission beginning"); if (errorcount == MAXERRORS) { xerror(); } while ((nbytes=inStream.read(sector))!=0) { if (nbytes<SECSIZE) sector[nbytes]=CPMEOF; errorcount = 0; while (errorcount < MAXERRORS) { errStream.println( "{" + blocknumber + "} "); putchar(SOH); /* here is our header */ putchar(blocknumber); /* the block number */ putchar(~blocknumber); /* & its complement */ checksum = 0; for (index = 0; index < SECSIZE; index++) { putchar(sector[index]); checksum += sector[index]; } putchar(checksum); /* tell our checksum */ if (getchar() != ACK) ++errorcount; else break; } if (errorcount == MAXERRORS) xerror(); ++blocknumber; } boolean isAck = false; while (!isAck) { putchar(EOT); isAck = getchar() == ACK; } errStream.println( "Transmission complete."); return true; } /* * receive a file from the remote */ public boolean receive(String tfile) throws IOException, InterruptedException { char checksum, index, blocknumber, errorcount; byte character; byte[] sector = new byte[SECSIZE]; DataOutputStream foo; foo = new DataOutputStream(new FileOutputStream(tfile)); System.out.println("you have " + SLEEP + " seconds..."); /* wait for the user or remote to get his act together */ gotChar = false; new IOTimer(SLEEP, "receive from remote").start(); errStream.println("Starting receive..."); putchar(NAK); errorcount = 0; blocknumber = 1; rxLoop: do { character = getchar(); gotChar = true; if (character != EOT) { try { byte not_ch; if (character != SOH) { errStream.println( "Not SOH"); if (++errorcount < MAXERRORS) continue rxLoop; else xerror(); } character = getchar(); not_ch = (byte)(~getchar()); errStream.println( "[" + character + "] "); if (character != not_ch) { errStream.println( "Blockcounts not ~"); ++errorcount; continue rxLoop; } if (character != blocknumber) { errStream.println( "Wrong blocknumber"); ++errorcount; continue rxLoop; } checksum = 0; for (index = 0; index < SECSIZE; index++) { sector[index] = getchar(); checksum += sector[index]; } if (checksum != getchar()) { errStream.println( "Bad checksum"); errorcount++; continue rxLoop; } putchar(ACK); blocknumber++; try { foo.write(sector); } catch (IOException e) { errStream.println("write failed, blocknumber " + blocknumber); } } finally { if (errorcount != 0) putchar(NAK); } } } while (character != EOT); foo.close(); putchar(ACK); /* tell the other end we accepted his EOT */ putchar(ACK); putchar(ACK); errStream.println("Receive Completed."); return true; } protected byte getchar() throws IOException { return (byte)inStream.read(); } protected void putchar(int c) throws IOException { outStream.write(c); } protected void xerror() { errStream.println("too many errors...aborting"); try { die(1); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } protected void die(int how) throws Exception { if (standalone) System.exit(how); else throw new Exception("Error code " + Integer.toString(how)); }
}
</source>
JModem - simple communications program
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
import java.awt.BorderLayout; import java.awt.Font; import java.awt.event.KeyEvent; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Writer; import java.util.Enumeration; import java.util.HashMap; import javax.rum.rumPortIdentifier; import javax.rum.PortInUseException; import javax.rum.SerialPort; import javax.rum.UnsupportedCommOperationException; import javax.swing.ButtonGroup; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; /**
* JModem - simple communications program. * WARNING this file was built with the NetBeans Developer IDE * and parts of it should not be modified with a text editor. * @author Ian F. Darwin, http://www.darwinsys.ru/ * @version $Id: JModem.java,v 1.18 2004/04/11 23:50:40 ian Exp $ */
public class JModem extends javax.swing.JFrame {
/** The Model. */ JMModel theModel; /** The TextArea */ JTextArea theTextArea; /** The courier font for the text areas and fields. */ protected Font plainFont; /** The valid baud rates (actually BPS rates). */ private int[] baudot = { 9600, 19200, 38400, 57600, 115200 }; /** The types of remote systems. */ private String sysTypes[] = { "Unix", "DOS", "Other" }; private int M_RECEIVE = -1, M_SEND = +1; private int xferDirection = M_RECEIVE; /** Constructor */ public JModem() { theModel = new JMModel(this); initComponents(); finishConstructor(); pack(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the FormEditor. */ private void initComponents () {//GEN-BEGIN:initComponents setTitle ("JModem"); addWindowListener (new java.awt.event.WindowAdapter () { public void windowClosing (java.awt.event.WindowEvent evt) { exitForm (evt); } } ); getContentPane ().setLayout (new java.awt.BorderLayout ()); jMenuBar1 = new javax.swing.JMenuBar (); fileMenu = new javax.swing.JMenu (); fileMenu.setText ("File"); saveLogFileMenuItem = new javax.swing.JMenuItem (); saveLogFileMenuItem.setText ("Save Log"); saveLogFileMenuItem.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { saveLogFileMenuItemActionPerformed (evt); } } ); fileMenu.add(saveLogFileMenuItem); fileMenu.addSeparator(); exitMenuItem = new javax.swing.JMenuItem (); exitMenuItem.setText ("Exit"); exitMenuItem.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { exitMenuItemActionPerformed (evt); } } ); fileMenu.add(exitMenuItem); jMenuBar1.add(fileMenu); helpMenu = new javax.swing.JMenu (); helpMenu.setText ("Help"); helpAboutMenuItem = new javax.swing.JMenuItem (); helpAboutMenuItem.setText ("Item"); helpAboutMenuItem.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { helpAboutMenuItemActionPerformed (evt); } } ); helpMenu.add(helpAboutMenuItem); jMenuBar1.add(helpMenu);
setJMenuBar(jMenuBar1); connectPanel = new javax.swing.JPanel (); connectPanel.setLayout (new java.awt.FlowLayout ()); connectPanelLabel = new javax.swing.JLabel (); connectPanelLabel.setText ("Connection"); connectPanelLabel.setForeground (java.awt.Color.red); connectPanel.add (connectPanelLabel); portsLabel = new javax.swing.JLabel (); portsLabel.setText ("Port:"); connectPanel.add (portsLabel); portsComboBox = new javax.swing.JComboBox (); portsComboBox.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { portsComboBoxActionPerformed (evt); } } ); connectPanel.add (portsComboBox); buadLabel = new javax.swing.JLabel (); buadLabel.setText ("Speed"); connectPanel.add (buadLabel); baudComboBox = new javax.swing.JComboBox (); baudComboBox.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { baudComboBoxActionPerformed (evt); } } ); connectPanel.add (baudComboBox); databitsPanel = new javax.swing.JPanel (); databitsPanel.setPreferredSize (new java.awt.Dimension(50, 50)); databitsPanel.setMinimumSize (new java.awt.Dimension(0, 0)); databitsPanel.setLayout (new javax.swing.BoxLayout (databitsPanel, 1)); d7RadioButton = new javax.swing.JRadioButton (); d7RadioButton.setText ("7"); databitsPanel.add (d7RadioButton); d8RadioButton = new javax.swing.JRadioButton (); d8RadioButton.setSelected (true); d8RadioButton.setText ("8"); databitsPanel.add (d8RadioButton); connectPanel.add (databitsPanel); parityPanel = new javax.swing.JPanel (); parityPanel.setPreferredSize (new java.awt.Dimension(50, 50)); parityPanel.setLayout (new javax.swing.BoxLayout (parityPanel, 1)); pNoneRadioButton = new javax.swing.JRadioButton (); pNoneRadioButton.setSelected (true); pNoneRadioButton.setText ("None"); pNoneRadioButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { pNoneRadioButtonActionPerformed (evt); } } ); parityPanel.add (pNoneRadioButton); pEvenRadioButton = new javax.swing.JRadioButton (); pEvenRadioButton.setText ("Even"); pEvenRadioButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { evenRadioButtonActionPerformed (evt); } } ); parityPanel.add (pEvenRadioButton); pOddRadioButton = new javax.swing.JRadioButton (); pOddRadioButton.setText ("Odd"); pOddRadioButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { oddRadioButtonActionPerformed (evt); } } ); parityPanel.add (pOddRadioButton); connectPanel.add (parityPanel); sysTypeLabel = new javax.swing.JLabel (); sysTypeLabel.setText ("Remote:"); connectPanel.add (sysTypeLabel); sysTypeComboBox = new javax.swing.JComboBox (); sysTypeComboBox.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { sysTypeComboBoxActionPerformed (evt); } } ); connectPanel.add (sysTypeComboBox); connectButton = new javax.swing.JButton (); connectButton.setText ("Connect"); connectButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { connectButtonActionPerformed (evt); } } ); connectPanel.add (connectButton); getContentPane().add(connectPanel, BorderLayout.NORTH); xferPanel = new javax.swing.JPanel (); xferPanel.setLayout (new java.awt.FlowLayout ()); xferPanelLabel = new javax.swing.JLabel (); xferPanelLabel.setText ("File Transfer"); xferPanelLabel.setForeground (java.awt.Color.red); xferPanel.add (xferPanelLabel); jPanel6 = new javax.swing.JPanel (); jPanel6.setLayout (new javax.swing.BoxLayout (jPanel6, 1)); sendRadioButton = new javax.swing.JRadioButton (); sendRadioButton.setSelected (true); sendRadioButton.setText ("Send"); sendRadioButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { sendRadioButtonActionPerformed (evt); } } ); jPanel6.add (sendRadioButton); recvRadioButton = new javax.swing.JRadioButton (); recvRadioButton.setText ("Receive"); recvRadioButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { recvRadioButtonActionPerformed (evt); } } ); jPanel6.add (recvRadioButton); xferPanel.add (jPanel6); xferFilenameLabel = new javax.swing.JLabel (); xferFilenameLabel.setText ("Filename:"); xferPanel.add (xferFilenameLabel); xferFileNameTF = new javax.swing.JTextField (); xferFileNameTF.setPreferredSize (new java.awt.Dimension(100, 20)); xferPanel.add (xferFileNameTF); jPanel7 = new javax.swing.JPanel (); jPanel7.setLayout (new javax.swing.BoxLayout (jPanel7, 1)); xferModeTextRadioButton = new javax.swing.JRadioButton (); xferModeTextRadioButton.setText ("Text"); jPanel7.add (xferModeTextRadioButton); xferModeBinRadioButton = new javax.swing.JRadioButton (); xferModeBinRadioButton.setSelected (true); xferModeBinRadioButton.setText ("Binary"); jPanel7.add (xferModeBinRadioButton); xferPanel.add (jPanel7); xferButton = new javax.swing.JButton (); xferButton.setText ("Transfer"); xferButton.addActionListener (new java.awt.event.ActionListener () { public void actionPerformed (java.awt.event.ActionEvent evt) { xferButtonActionPerformed (evt); } } ); xferPanel.add (xferButton); getContentPane ().add (xferPanel, BorderLayout.SOUTH); }//GEN-END:initComponents /** Save the session log to disk. */ private void saveLogFileMenuItemActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveLogFileMenuItemActionPerformed theModel.saveLogFile(); }//GEN-LAST:event_saveLogFileMenuItemActionPerformed private void helpAboutMenuItemActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_helpAboutMenuItemActionPerformed note("JModem 0.0 (c) 2000 Ian F. Darwin\nhttp://www.darwinsys.ru/"); }//GEN-LAST:event_helpAboutMenuItemActionPerformed private void baudComboBoxActionPerformed (java.awt.event.ActionEvent evt) { // Add your handling code here: } private void portsComboBoxActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_portsComboBoxActionPerformed // Add your handling code here: }//GEN-LAST:event_portsComboBoxActionPerformed /** A TextArea subclass with funky keypress forwarding: send to * remote, not to local. This IS a terminal emulator, after all. */ class MyTextArea extends JTextArea { MyTextArea(int r, int c) { super(r, c); } /** Handle local KeyEvents: send KeyTyped to the remote. */ protected void processComponentKeyEvent(java.awt.event.KeyEvent evt) { if (evt.getID() != KeyEvent.KEY_TYPED) return; // send keystrokes to remote, for processing. // do nothing locally, to avoid user keystrokes appearing twice! if (theModel.state != JMModel.S_CONNECTED) { getToolkit().beep(); // or just connect()? return; } char ch = evt.getKeyChar(); if (ch == "\n") { // XX if systemtype == dos // sendChar("\r"); theModel.sendChar("\n"); return; } theModel.sendChar(ch); } } /** Finish the initializations. */ private void finishConstructor() { // Create the textarea with a JScrollpane wrapping it. // Install it in Centre of the TextArea. theTextArea = new MyTextArea(20, 80); getContentPane().add(new JScrollPane(theTextArea), BorderLayout.CENTER); plainFont = new Font("courier", Font.PLAIN, 13); theTextArea.setFont(plainFont); xferFileNameTF.setFont(plainFont); theModel.populateComboBox(); portsComboBox.setSelectedIndex(0); // Load up the baud rate combo box for (int i=0; i<baudot.length; i++) { baudComboBox.addItem(Integer.toString(baudot[i])); } baudComboBox.setSelectedIndex(0); // Load up the System Type combo box for (int i=0; i<sysTypes.length; i++) { sysTypeComboBox.addItem(sysTypes[i]); } sysTypeComboBox.setSelectedIndex(0); // put radio buttons into groups to enforce single-selection ButtonGroup b1 = new ButtonGroup(); b1.add(d7RadioButton); b1.add(d8RadioButton); ButtonGroup b2 = new ButtonGroup(); b2.add(pNoneRadioButton); b2.add(pEvenRadioButton); b2.add(pOddRadioButton); ButtonGroup b3 = new ButtonGroup(); b3.add(sendRadioButton); b3.add(recvRadioButton); ButtonGroup b4 = new ButtonGroup(); b4.add(xferModeTextRadioButton); b4.add(xferModeBinRadioButton); xferModeBinRadioButton.setEnabled(true); } private void recvRadioButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recvRadioButtonActionPerformed xferDirection = M_RECEIVE; }//GEN-LAST:event_recvRadioButtonActionPerformed private void sendRadioButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendRadioButtonActionPerformed xferDirection = M_SEND; }//GEN-LAST:event_sendRadioButtonActionPerformed private void exitMenuItemActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed System.exit(0); }//GEN-LAST:event_exitMenuItemActionPerformed private void sysTypeComboBoxActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sysTypeComboBoxActionPerformed // Add your handling code here: }//GEN-LAST:event_sysTypeComboBoxActionPerformed private void pNoneRadioButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pNoneRadioButtonActionPerformed // Add your handling code here: }//GEN-LAST:event_pNoneRadioButtonActionPerformed private void oddRadioButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_oddRadioButtonActionPerformed // Add your handling code here: }//GEN-LAST:event_oddRadioButtonActionPerformed private void evenRadioButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_evenRadioButtonActionPerformed // Add your handling code here: }//GEN-LAST:event_evenRadioButtonActionPerformed
/** This method basically toggles between Connected mode and * disconnected mode. */ private void connectButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectButtonActionPerformed if (theModel.state == JMModel.S_CONNECTED) { theModel.disconnect(); // calls our disconnect() if OK } else { theModel.connect(); // calls our connect() if OK } }//GEN-LAST:event_connectButtonActionPerformed /** Show that we have connected to the serial port. */ void connect() { connectButton.setText("Disconnect"); theTextArea.setEditable(true); theTextArea.requestFocus(); } /** Show that we have connected to the serial port. */ void disconnect() { connectButton.setText("Connect"); theTextArea.setEditable(false); } private void xferButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xferButtonActionPerformed // Do the transfer, using TModem class. theModel.xfer(); }//GEN-LAST:event_xferButtonActionPerformed /** Exit the Application */ private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm System.exit (0); }//GEN-LAST:event_exitForm
// Some of these must be package-level visibility for JMModel, // until we re-define the interface to that class a little... // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel connectPanel; private javax.swing.JPanel xferPanel; private javax.swing.JLabel connectPanelLabel; private javax.swing.JLabel portsLabel; protected javax.swing.JComboBox portsComboBox; private javax.swing.JLabel buadLabel; protected javax.swing.JComboBox baudComboBox; private javax.swing.JPanel databitsPanel; private javax.swing.JPanel parityPanel; private javax.swing.JLabel sysTypeLabel; private javax.swing.JComboBox sysTypeComboBox; private javax.swing.JButton connectButton; private javax.swing.JRadioButton d7RadioButton; private javax.swing.JRadioButton d8RadioButton; private javax.swing.JRadioButton pNoneRadioButton; private javax.swing.JRadioButton pEvenRadioButton; private javax.swing.JRadioButton pOddRadioButton; private javax.swing.JLabel xferPanelLabel; private javax.swing.JPanel jPanel6; private javax.swing.JLabel xferFilenameLabel; private javax.swing.JTextField xferFileNameTF; private javax.swing.JPanel jPanel7; private javax.swing.JButton xferButton; private javax.swing.JRadioButton sendRadioButton; private javax.swing.JRadioButton recvRadioButton; private javax.swing.JRadioButton xferModeTextRadioButton; private javax.swing.JRadioButton xferModeBinRadioButton; private javax.swing.JMenuBar jMenuBar1; private javax.swing.JMenu fileMenu; private javax.swing.JMenu helpMenu; private javax.swing.JMenuItem saveLogFileMenuItem; private javax.swing.JMenuItem exitMenuItem; private javax.swing.JMenuItem helpAboutMenuItem;
// End of variables declaration//GEN-END:variables
/** Tell if the user wants 7 or 8-bit words */ public int getDataBits() { if (d7RadioButton.isSelected()) return 7; if (d8RadioButton.isSelected()) return 8; throw new IllegalStateException("No word size in radio button group"); } /** Tell if the user wants even, odd, or no parity. */ public int getParity() { if (pNoneRadioButton.isSelected()) return JMModel.PARITY_NONE; if (pEvenRadioButton.isSelected()) return JMModel.PARITY_EVEN; if (pOddRadioButton.isSelected()) return JMModel.PARITY_ODD; throw new IllegalStateException("No parity in radio button group"); } /** Get the filename */ public String getXferFileName() { return xferFileNameTF.getText(); } /** "One if by send, two if receive" */ public boolean isSend() { if (sendRadioButton.isSelected()) return true; if (recvRadioButton.isSelected()) return false; throw new IllegalStateException("No send/recv set in radio button group"); } /** Convenience routine: Show a standard-form information dialog */ void note(String message) { JOptionPane.showMessageDialog(this, message, "JModem Notice", JOptionPane.INFORMATION_MESSAGE); return; } /** Convenience routine: Show a standard-form error dialog */ void err(String message) { JOptionPane.showMessageDialog(this, message, "JModem Error", JOptionPane.ERROR_MESSAGE); return; } /** Main: just create and show the application class. */ public static void main(java.lang.String[] args) { new JModem().setVisible(true); }
} /**
* JMModel -- Communications I/O for JModem. No GUI stuff here. * @author Ian F. Darwin, http://www.darwinsys.ru/ * @version $Id: JMModel.java,v 1.4 2004/04/11 23:50:40 ian Exp $ */
class JMModel extends java.lang.Object {
/** The View */ JModem theGUI; /** The javax.ru.rumPort object in use */ private SerialPort thePort; /** The input and output streams */ private InputStream serialInput; private OutputStream serialOutput; /** The size of the static read buffer. */ protected static final int BUFSIZE = 1024; /** A buffer for the read listener; preallocated once. */ static byte[] buf = new byte[BUFSIZE]; /** A Thread for reading from the remote. */ protected Thread serialReadThread; /** A file transfer program */ protected TModem xferProg; /** The state for disconnected and connected */ static int S_DISCONNECTED = 0, S_CONNECTED = 1; /** The state, either disconnected or connected */ int state = S_DISCONNECTED; /** The substate settings */ static int S_INTERACT = 0, S_XFER = 1; /** The online state, either interactive or in xfer. Used by the * main reader thread to avoid reading data meant for the xfer program. */ int submode = S_INTERACT; // Constants to hide the Comm API from our GUI. public final static int PARITY_NONE = SerialPort.PARITY_NONE; public final static int PARITY_EVEN = SerialPort.PARITY_EVEN; public final static int PARITY_ODD = SerialPort.PARITY_ODD; private int[] baudot = { 9600, 19200, 38400, 57600, 115200 }; private String sysTypes[] = { "Unix", "DOS", "Other" }; protected HashMap portsIDmap = new HashMap(); /** Constructor */ public JMModel(JModem gui) { theGUI = gui; } protected String DEFAULT_LOG_FILE = "jmodemlog.txt";; /** Use normal java.io to save the JTextArea"s session log * into a file. */ public void saveLogFile() { String fileName = DEFAULT_LOG_FILE; try { Writer w = new FileWriter(fileName); theGUI.theTextArea.write(w); w.write("\r"); w.write("\n"); // in case last line is a prompt. w.close(); } catch (IOException e) { theGUI.err("Error saving log file:\n" + e.toString()); return; } theGUI.note("Session log saved to " + fileName); } /** Load the list of Serial Ports into the chooser. * This code is far too chummy with the innards of class JModem. */ void populateComboBox() { // get list of ports available on this particular computer, // by calling static method in CommPortIdentifier. Enumeration pList = CommPortIdentifier.getPortIdentifiers(); // Process the list of ports, putting serial ports into ComboBox while (pList.hasMoreElements()) { CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement(); if (cpi.getPortType() == CommPortIdentifier.PORT_SERIAL) { theGUI.portsComboBox.addItem(cpi.getName()); portsIDmap.put(cpi.getName(), cpi); } } } /** Connect to the chosen serial port, and set parameters. */ void connect() { try { // Open the specified serial port CommPortIdentifier cpi = (CommPortIdentifier)portsIDmap.get( theGUI.portsComboBox.getSelectedItem()); thePort = (SerialPort)cpi.open("JModem", 15*1000); // Set the serial port parameters. thePort.setSerialPortParams( baudot[theGUI.baudComboBox.getSelectedIndex()], // baud theGUI.getDataBits() == 7 ? SerialPort.DATABITS_7 : SerialPort.DATABITS_8, SerialPort.STOPBITS_1, // stop bits theGUI.getParity()); // parity thePort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN & SerialPort.FLOWCONTROL_RTSCTS_OUT); } catch (PortInUseException pue) { theGUI.err("Port in use: close other app, or use different port."); return; } catch (UnsupportedCommOperationException uoe) { theGUI.err("Unsupported options error: try different settings"); return; } // Similar to "raw" mode: return when 1 or more chars available. try { thePort.enableReceiveThreshold(1); if (!thePort.isReceiveThresholdEnabled()) { theGUI.err("Could not set receive threshold"); disconnect(); return; } thePort.setInputBufferSize(buf.length); } catch (UnsupportedCommOperationException ev) { theGUI.err("Unable to set receive threshold in Comm API; port unusable."); disconnect(); return; } // Get the streams try { serialInput = thePort.getInputStream(); } catch (IOException e) { theGUI.err("Error getting input stream:\n" + e.toString()); return; } try { serialOutput = thePort.getOutputStream(); } catch (IOException e) { theGUI.err("Error getting output stream:\n" + e.toString()); return; } // Now that we"re all set, create a Thread to read data from the remote serialReadThread = new Thread(new Runnable() { int nbytes = buf.length; public void run() { do { try { // If the xfer program is running, stay out of its way. if (submode == S_XFER) { delay(1000); continue; } nbytes = serialInput.read(buf, 0, buf.length); } catch (IOException ev) { theGUI.err("Error reading from remote:\n" + ev.toString()); return; } // XXX need an appendChar() method in MyTextArea String tmp = new String(buf, 0, nbytes); theGUI.theTextArea.append(tmp); theGUI.theTextArea.setCaretPosition( theGUI.theTextArea.getText().length()); } while (serialInput != null); } }); serialReadThread.start(); // Finally, tell rest of program, and user, that we"re online. state = S_CONNECTED; theGUI.connect(); } /** Break our connection to the serial port. */ void disconnect() { // Tell java.io we are done with the input and output try { serialReadThread.stop(); // IGNORE DEPRECATION WARNINGS; the Java // API still lacks a reliable termination method for Threads // that are blocked on e.g., local disk reads. serialInput.close(); serialOutput.close(); serialOutput = null; } catch (IOException e) { theGUI.err("IO Exception closing port:\n" + e.toString()); } // Tell javax.rum we are done with the port. thePort.removeEventListener(); thePort.close(); // Discard TModem object, if present. xferProg = null; // Tell rest of program we are no longer online. state = S_DISCONNECTED; theGUI.disconnect(); } /** Convenience routine, due to useless InterruptedException */ public void delay(long milliseconds) { try { Thread.sleep(milliseconds); } catch (InterruptedException e) { // can"t happen } } /** Send one character to the remote */ void sendChar(char ch) { if (state != S_CONNECTED) return; // System.err.println("--> " + ch); try { serialOutput.write(ch); } catch (IOException e) { theGUI.err("Output error on remote:\n" + e.toString() + "\nClosing connection."); disconnect(); } } /** Send a String of characters to the remote. */ private void sendString(String s) { if (state != S_CONNECTED) return; try { serialOutput.write(s.getBytes()); } catch (IOException e) { theGUI.err("Output error on remote:\n" + e.toString() + "\nClosing connection."); disconnect(); } } /** Do one complete file transfer, using TModem */ public void xfer() { if (state != S_CONNECTED) { theGUI.err("Must be connected to do file transfers"); return; } if (xferProg == null) { xferProg = new TModem(serialInput, serialOutput, new PrintWriter(System.out)); // xerProg discarded in disconnect() } String fileName = theGUI.getXferFileName(); if (fileName.length() == 0) { theGUI.err("Filename must be given"); return; } // Do the transfer! If we are sending, send a "tmodem -r" to // the other side; if receiving, send "tmodem -s" to ask it // to send the file. try { if (theGUI.isSend()) { if (!new File(fileName).canRead()) { theGUI.err("Can"t read file " + fileName + "."); return; } // Other end must "r"eceive what we send. sendString("tmodem -r " + fileName + "\r\n"); delay(500); // let command echo back to us submode = S_XFER; xferProg.send(fileName); } else { // Other end must send for us to receive. sendString("tmodem -s " + fileName + "\r\n"); delay(500); // let command echo back to us submode = S_XFER; xferProg.receive(fileName); } } catch (InterruptedException e) { theGUI.err("Timeout"); return; } catch (IOException e) { theGUI.err("IO Exception in transfer:\n" + e); return; } catch (Exception ev) { theGUI.err("Protocol failure:\n" + ev); return; } finally { submode = S_INTERACT; } theGUI.note("File Transfer completed"); }
}
/**
* a tiny version of Ward Christensen"s MODEM program for UNIX. * Written ~ 1980 by Andrew Scott Beals. Last revised 1982. * A.D. 2000 - dragged from the archives for use in Java Cookbook. * * @author C version by Andrew Scott Beals, sjobrg.andy%mit-oz@mit-mc.arpa. * @author Java version by Ian F. Darwin, ian@darwinsys.ru * $Id: TModem.java,v 1.8 2000/03/02 03:40:50 ian Exp $ */
class TModem {
protected final byte CPMEOF = 26; /* control/z */ protected final int MAXERRORS = 10; /* max times to retry one block */ protected final int SECSIZE = 128; /* cpm sector, transmission block */ protected final int SENTIMOUT = 30; /* timeout time in send */ protected final int SLEEP = 30; /* timeout time in recv */ /* Protocol characters used */ protected final byte SOH = 1; /* Start Of Header */ protected final byte EOT = 4; /* End Of Transmission */ protected final byte ACK = 6; /* ACKnowlege */ protected final byte NAK = 0x15; /* Negative AcKnowlege */ protected InputStream inStream; protected OutputStream outStream; protected PrintWriter errStream; /** Construct a TModem */ public TModem(InputStream is, OutputStream os, PrintWriter errs) { inStream = is; outStream = os; errStream = errs; } /** Construct a TModem with default files (stdin and stdout). */ public TModem() { inStream = System.in; outStream = System.out; errStream = new PrintWriter(System.err); } /** A main program, for direct invocation. */ public static void main(String[] argv) throws IOException, InterruptedException { /* argc must == 2, i.e., `java TModem -s filename" */ if (argv.length != 2) usage(); if (argv[0].charAt(0) != "-") usage(); TModem tm = new TModem(); tm.setStandalone(true); boolean OK = false; switch (argv[0].charAt(1)){ case "r": OK = tm.receive(argv[1]); break; case "s": OK = tm.send(argv[1]); break; default: usage(); } System.out.print(OK?"Done OK":"Failed"); System.exit(0); } /* give user minimal usage message */ protected static void usage() { System.err.println("usage: TModem -r/-s file"); // not errStream, not die(), since this is static. System.exit(1); } /** If we"re in a standalone app it is OK to System.exit() */ protected boolean standalone = false; public void setStandalone(boolean is) { standalone = is; } public boolean isStandalone() { return standalone; } /** A flag used to communicate with inner class IOTimer */ protected boolean gotChar; /** An inner class to provide a read timeout for alarms. */ class IOTimer extends Thread { String message; long milliseconds; /** Construct an IO Timer */ IOTimer(long sec, String mesg) { milliseconds = 1000 * sec; message = mesg; } public void run() { try { Thread.sleep(milliseconds); } catch (InterruptedException e) { // can"t happen } /** Implement the timer */ if (!gotChar) errStream.println("Timed out waiting for " + message); die(1); } } /* * send a file to the remote */ public boolean send(String tfile) throws IOException, InterruptedException { char checksum, index, blocknumber, errorcount; byte character; byte[] sector = new byte[SECSIZE]; int nbytes; DataInputStream foo; foo = new DataInputStream(new FileInputStream(tfile)); errStream.println( "file open, ready to send"); errorcount = 0; blocknumber = 1; // The C version uses "alarm()", a UNIX-only system call, // to detect if the read times out. Here we do detect it // by using a Thread, the IOTimer class defined above. gotChar = false; new IOTimer(SENTIMOUT, "NAK to start send").start(); do { character = getchar(); gotChar = true; if (character != NAK && errorcount < MAXERRORS) ++errorcount; } while (character != NAK && errorcount < MAXERRORS); errStream.println( "transmission beginning"); if (errorcount == MAXERRORS) { xerror(); } while ((nbytes=inStream.read(sector))!=0) { if (nbytes<SECSIZE) sector[nbytes]=CPMEOF; errorcount = 0; while (errorcount < MAXERRORS) { errStream.println( "{" + blocknumber + "} "); putchar(SOH); /* here is our header */ putchar(blocknumber); /* the block number */ putchar(~blocknumber); /* & its complement */ checksum = 0; for (index = 0; index < SECSIZE; index++) { putchar(sector[index]); checksum += sector[index]; } putchar(checksum); /* tell our checksum */ if (getchar() != ACK) ++errorcount; else break; } if (errorcount == MAXERRORS) xerror(); ++blocknumber; } boolean isAck = false; while (!isAck) { putchar(EOT); isAck = getchar() == ACK; } errStream.println( "Transmission complete."); return true; } /* * receive a file from the remote */ public boolean receive(String tfile) throws IOException, InterruptedException { char checksum, index, blocknumber, errorcount; byte character; byte[] sector = new byte[SECSIZE]; DataOutputStream foo; foo = new DataOutputStream(new FileOutputStream(tfile)); System.out.println("you have " + SLEEP + " seconds..."); /* wait for the user or remote to get his act together */ gotChar = false; new IOTimer(SLEEP, "receive from remote").start(); errStream.println("Starting receive..."); putchar(NAK); errorcount = 0; blocknumber = 1; rxLoop: do { character = getchar(); gotChar = true; if (character != EOT) { try { byte not_ch; if (character != SOH) { errStream.println( "Not SOH"); if (++errorcount < MAXERRORS) continue rxLoop; else xerror(); } character = getchar(); not_ch = (byte)(~getchar()); errStream.println( "[" + character + "] "); if (character != not_ch) { errStream.println( "Blockcounts not ~"); ++errorcount; continue rxLoop; } if (character != blocknumber) { errStream.println( "Wrong blocknumber"); ++errorcount; continue rxLoop; } checksum = 0; for (index = 0; index < SECSIZE; index++) { sector[index] = getchar(); checksum += sector[index]; } if (checksum != getchar()) { errStream.println( "Bad checksum"); errorcount++; continue rxLoop; } putchar(ACK); blocknumber++; try { foo.write(sector); } catch (IOException e) { errStream.println("write failed, blocknumber " + blocknumber); } } finally { if (errorcount != 0) putchar(NAK); } } } while (character != EOT); foo.close(); putchar(ACK); /* tell the other end we accepted his EOT */ putchar(ACK); putchar(ACK); errStream.println("Receive Completed."); return true; } protected byte getchar() throws IOException { return (byte)inStream.read(); } protected void putchar(int c) throws IOException { outStream.write(c); } protected void xerror() { errStream.println("too many errors...aborting"); die(1); } protected void die(int how) { if (standalone) System.exit(how); else System.out.println(("Error code " + how)); }
}
</source>
Print to a serial port using Java Communications
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
import java.awt.BorderLayout; import java.awt.Container; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.Enumeration; import java.util.HashMap; import javax.rum.rumPort; import javax.rum.rumPortIdentifier; import javax.rum.NoSuchPortException; import javax.rum.ParallelPort; import javax.rum.PortInUseException; import javax.rum.SerialPort; import javax.rum.UnsupportedCommOperationException; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; /**
* Print to a serial port using Java Communications. * * @author Ian F. Darwin, http://www.darwinsys.ru/ */
public class ParallelPrint extends CommPortOpen {
protected static String inputFileName; public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { if (argv.length != 1) { System.err.println("Usage: ParallelPrint filename"); System.exit(1); } inputFileName = argv[0]; new ParallelPrint(null).converse(); System.exit(0); } /* Constructor */ public ParallelPrint(JFrame f) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { super(f); } /** * Hold the (one-way) conversation. */ protected void converse() throws IOException { // Make a reader for the input file. BufferedReader file = new BufferedReader( new FileReader(inputFileName)); String line; while ((line = file.readLine()) != null) os.println(line); // Finally, clean up. file.close(); os.close(); }
}
class CommPortOpen {
/** How long to wait for the open to finish up. */ public static final int TIMEOUTSECONDS = 30; /** The baud rate to use. */ public static final int BAUD = 19200; /** The parent JFrame, for the chooser. */ protected JFrame parent; /** The input stream */ protected BufferedReader is; /** The output stream */ protected PrintStream os; /** The chosen Port Identifier */ CommPortIdentifier thePortID; /** The chosen Port itself */ CommPort thePort; public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { new CommPortOpen(null).converse(); System.exit(0); } /* Constructor */ public CommPortOpen(JFrame f) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { // Use the PortChooser from before. Pop up the JDialog. PortChooser chooser = new PortChooser(null); String portName = null; do { chooser.setVisible(true); // Dialog done. Get the port name. portName = chooser.getSelectedName(); if (portName == null) System.out.println("No port selected. Try again.\n"); } while (portName == null); // Get the CommPortIdentifier. thePortID = chooser.getSelectedIdentifier(); // Now actually open the port. // This form of openPort takes an Application Name and a timeout. // System.out.println("Trying to open " + thePortID.getName() + "..."); switch (thePortID.getPortType()) { case CommPortIdentifier.PORT_SERIAL: thePort = thePortID.open("DarwinSys DataComm", TIMEOUTSECONDS * 1000); SerialPort myPort = (SerialPort) thePort; // set up the serial port myPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); break; case CommPortIdentifier.PORT_PARALLEL: thePort = thePortID.open("DarwinSys Printing", TIMEOUTSECONDS * 1000); ParallelPort pPort = (ParallelPort)thePort; // Tell API to pick "best available mode" - can fail! // myPort.setMode(ParallelPort.LPT_MODE_ANY); // Print what the mode is int mode = pPort.getMode(); switch (mode) { case ParallelPort.LPT_MODE_ECP: System.out.println("Mode is: ECP"); break; case ParallelPort.LPT_MODE_EPP: System.out.println("Mode is: EPP"); break; case ParallelPort.LPT_MODE_NIBBLE: System.out.println("Mode is: Nibble Mode."); break; case ParallelPort.LPT_MODE_PS2: System.out.println("Mode is: Byte mode."); break; case ParallelPort.LPT_MODE_SPP: System.out.println("Mode is: Compatibility mode."); break; // ParallelPort.LPT_MODE_ANY is a "set only" mode; // tells the API to pick "best mode"; will report the // actual mode it selected. default: throw new IllegalStateException("Parallel mode " + mode + " invalid."); } break; default: // Neither parallel nor serial?? throw new IllegalStateException("Unknown port type " + thePortID); } // Get the input and output streams // Printers can be write-only try { is = new BufferedReader(new InputStreamReader(thePort.getInputStream())); } catch (IOException e) { System.err.println("Can"t open input stream: write-only"); is = null; } os = new PrintStream(thePort.getOutputStream(), true); } /** This method will be overridden by non-trivial subclasses * to hold a conversation. */ protected void converse() throws IOException { System.out.println("Ready to read and write port."); // Input/Output code not written -- must subclass. // Finally, clean up. if (is != null) is.close(); os.close(); }
} class PortChooser extends JDialog implements ItemListener {
/** A mapping from names to CommPortIdentifiers. */ protected HashMap map = new HashMap(); /** The name of the choice the user made. */ protected String selectedPortName; /** The CommPortIdentifier the user chose. */ protected CommPortIdentifier selectedPortIdentifier; /** The JComboBox for serial ports */ protected JComboBox serialPortsChoice; /** The JComboBox for parallel ports */ protected JComboBox parallelPortsChoice; /** The JComboBox for anything else */ protected JComboBox other; /** The SerialPort object */ protected SerialPort ttya; /** To display the chosen */ protected JLabel choice; /** Padding in the GUI */ protected final int PAD = 5; /** This will be called from either of the JComboBoxen when the * user selects any given item. */ public void itemStateChanged(ItemEvent e) { // Get the name selectedPortName = (String)((JComboBox)e.getSource()).getSelectedItem(); // Get the given CommPortIdentifier selectedPortIdentifier = (CommPortIdentifier)map.get(selectedPortName); // Display the name. choice.setText(selectedPortName); } /* The public "getter" to retrieve the chosen port by name. */ public String getSelectedName() { return selectedPortName; } /* The public "getter" to retrieve the selection by CommPortIdentifier. */ public CommPortIdentifier getSelectedIdentifier() { return selectedPortIdentifier; } /** A test program to show up this chooser. */ public static void main(String[] ap) { PortChooser c = new PortChooser(null); c.setVisible(true); // blocking wait System.out.println("You chose " + c.getSelectedName() + " (known by " + c.getSelectedIdentifier() + ")."); System.exit(0); } /** Construct a PortChooser --make the GUI and populate the ComboBoxes. */ public PortChooser(JFrame parent) { super(parent, "Port Chooser", true); makeGUI(); populate(); finishGUI(); } /** Build the GUI. You can ignore this for now if you have not * yet worked through the GUI chapter. Your mileage may vary. */ protected void makeGUI() { Container cp = getContentPane(); JPanel centerPanel = new JPanel(); cp.add(BorderLayout.CENTER, centerPanel); centerPanel.setLayout(new GridLayout(0,2, PAD, PAD)); centerPanel.add(new JLabel("Serial Ports", JLabel.RIGHT)); serialPortsChoice = new JComboBox(); centerPanel.add(serialPortsChoice); serialPortsChoice.setEnabled(false); centerPanel.add(new JLabel("Parallel Ports", JLabel.RIGHT)); parallelPortsChoice = new JComboBox(); centerPanel.add(parallelPortsChoice); parallelPortsChoice.setEnabled(false); centerPanel.add(new JLabel("Unknown Ports", JLabel.RIGHT)); other = new JComboBox(); centerPanel.add(other); other.setEnabled(false); centerPanel.add(new JLabel("Your choice:", JLabel.RIGHT)); centerPanel.add(choice = new JLabel()); JButton okButton; cp.add(BorderLayout.SOUTH, okButton = new JButton("OK")); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { PortChooser.this.dispose(); } }); } /** Populate the ComboBoxes by asking the Java Communications API * what ports it has. Since the initial information comes from * a Properties file, it may not exactly reflect your hardware. */ protected void populate() { // get list of ports available on this particular computer, // by calling static method in CommPortIdentifier. Enumeration pList = CommPortIdentifier.getPortIdentifiers(); // Process the list, putting serial and parallel into ComboBoxes while (pList.hasMoreElements()) { CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement(); // System.out.println("Port " + cpi.getName()); map.put(cpi.getName(), cpi); if (cpi.getPortType() == CommPortIdentifier.PORT_SERIAL) { serialPortsChoice.setEnabled(true); serialPortsChoice.addItem(cpi.getName()); } else if (cpi.getPortType() == CommPortIdentifier.PORT_PARALLEL) { parallelPortsChoice.setEnabled(true); parallelPortsChoice.addItem(cpi.getName()); } else { other.setEnabled(true); other.addItem(cpi.getName()); } } serialPortsChoice.setSelectedIndex(-1); parallelPortsChoice.setSelectedIndex(-1); } protected void finishGUI() { serialPortsChoice.addItemListener(this); parallelPortsChoice.addItemListener(this); other.addItemListener(this); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
}
</source>
Subclasses CommPortOpen and adds send/expect handling for dealing with Hayes-type modems
<source lang="java">
import java.awt.BorderLayout; import java.awt.Container; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.Enumeration; import java.util.HashMap; import javax.rum.rumPort; import javax.rum.rumPortIdentifier; import javax.rum.NoSuchPortException; import javax.rum.ParallelPort; import javax.rum.PortInUseException; import javax.rum.SerialPort; import javax.rum.UnsupportedCommOperationException; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; /**
* Subclasses CommPortOpen and adds send/expect handling for dealing * with Hayes-type modems. * * @author Ian F. Darwin, http://www.darwinsys.ru/ */ class CommPortModem extends CommPortOpen { /** The last line read from the serial port. */ protected String response; /** A flag to control debugging output. */ protected boolean debug = true; public CommPortModem(JFrame f) throws IOException, NoSuchPortException,PortInUseException, UnsupportedCommOperationException { super(f); } /** Send a line to a PC-style modem. Send \r\n, regardless of * what platform we"re on, instead of using println(). */ protected void send(String s) throws IOException { if (debug) { System.out.print(">>> "); System.out.print(s); System.out.println(); } os.print(s); os.print("\r\n"); // Expect the modem to echo the command. if (!expect(s)) { System.err.println("WARNING: Modem did not echo command."); } // The modem sends an extra blank line by way of a prompt. // Here we read and discard it. String junk = is.readLine(); if (junk.length() != 0) { System.err.print("Warning: unexpected response: "); System.err.println(junk); } } /** Read a line, saving it in "response". * @return true if the expected String is contained in the response, false if not. */ protected boolean expect(String exp) throws IOException { response = is.readLine(); if (debug) { System.out.print("<<< "); System.out.print(response); System.out.println(); } return response.indexOf(exp) >= 0; }
} /**
* Dial a phone using the Java Communications Package. * * @author Ian F. Darwin, http://www.darwinsys.ru/ */
public class CommPortDial extends CommPortModem {
protected static String number = "000-0000"; public static void main(String[] ap) throws IOException, NoSuchPortException,PortInUseException, UnsupportedCommOperationException { if (ap.length == 1) number = ap[0]; new CommPortDial().converse(); System.exit(0); } public CommPortDial() throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { super(null); } protected void converse() throws IOException { String resp; // the modem response. // Send the reset command send("ATZ"); expect("OK"); send("ATDT" + number); expect("OK"); try { Thread.sleep(5000); } catch (InterruptedException e) { // nothing to do } is.close(); os.close(); }
} class CommPortOpen {
/** How long to wait for the open to finish up. */ public static final int TIMEOUTSECONDS = 30; /** The baud rate to use. */ public static final int BAUD = 19200; /** The parent JFrame, for the chooser. */ protected JFrame parent; /** The input stream */ protected BufferedReader is; /** The output stream */ protected PrintStream os; /** The chosen Port Identifier */ CommPortIdentifier thePortID; /** The chosen Port itself */ CommPort thePort; public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { new CommPortOpen(null).converse(); System.exit(0); } /* Constructor */ public CommPortOpen(JFrame f) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { // Use the PortChooser from before. Pop up the JDialog. PortChooser chooser = new PortChooser(null); String portName = null; do { chooser.setVisible(true); // Dialog done. Get the port name. portName = chooser.getSelectedName(); if (portName == null) System.out.println("No port selected. Try again.\n"); } while (portName == null); // Get the CommPortIdentifier. thePortID = chooser.getSelectedIdentifier(); // Now actually open the port. // This form of openPort takes an Application Name and a timeout. // System.out.println("Trying to open " + thePortID.getName() + "..."); switch (thePortID.getPortType()) { case CommPortIdentifier.PORT_SERIAL: thePort = thePortID.open("DarwinSys DataComm", TIMEOUTSECONDS * 1000); SerialPort myPort = (SerialPort) thePort; // set up the serial port myPort.setSerialPortParams(BAUD, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); break; case CommPortIdentifier.PORT_PARALLEL: thePort = thePortID.open("DarwinSys Printing", TIMEOUTSECONDS * 1000); ParallelPort pPort = (ParallelPort)thePort; // Tell API to pick "best available mode" - can fail! // myPort.setMode(ParallelPort.LPT_MODE_ANY); // Print what the mode is int mode = pPort.getMode(); switch (mode) { case ParallelPort.LPT_MODE_ECP: System.out.println("Mode is: ECP"); break; case ParallelPort.LPT_MODE_EPP: System.out.println("Mode is: EPP"); break; case ParallelPort.LPT_MODE_NIBBLE: System.out.println("Mode is: Nibble Mode."); break; case ParallelPort.LPT_MODE_PS2: System.out.println("Mode is: Byte mode."); break; case ParallelPort.LPT_MODE_SPP: System.out.println("Mode is: Compatibility mode."); break; // ParallelPort.LPT_MODE_ANY is a "set only" mode; // tells the API to pick "best mode"; will report the // actual mode it selected. default: throw new IllegalStateException("Parallel mode " + mode + " invalid."); } break; default: // Neither parallel nor serial?? throw new IllegalStateException("Unknown port type " + thePortID); } // Get the input and output streams // Printers can be write-only try { is = new BufferedReader(new InputStreamReader(thePort.getInputStream())); } catch (IOException e) { System.err.println("Can"t open input stream: write-only"); is = null; } os = new PrintStream(thePort.getOutputStream(), true); } /** This method will be overridden by non-trivial subclasses * to hold a conversation. */ protected void converse() throws IOException { System.out.println("Ready to read and write port."); // Input/Output code not written -- must subclass. // Finally, clean up. if (is != null) is.close(); os.close(); }
} class PortChooser extends JDialog implements ItemListener {
/** A mapping from names to CommPortIdentifiers. */ protected HashMap map = new HashMap(); /** The name of the choice the user made. */ protected String selectedPortName; /** The CommPortIdentifier the user chose. */ protected CommPortIdentifier selectedPortIdentifier; /** The JComboBox for serial ports */ protected JComboBox serialPortsChoice; /** The JComboBox for parallel ports */ protected JComboBox parallelPortsChoice; /** The JComboBox for anything else */ protected JComboBox other; /** The SerialPort object */ protected SerialPort ttya; /** To display the chosen */ protected JLabel choice; /** Padding in the GUI */ protected final int PAD = 5; /** This will be called from either of the JComboBoxen when the * user selects any given item. */ public void itemStateChanged(ItemEvent e) { // Get the name selectedPortName = (String)((JComboBox)e.getSource()).getSelectedItem(); // Get the given CommPortIdentifier selectedPortIdentifier = (CommPortIdentifier)map.get(selectedPortName); // Display the name. choice.setText(selectedPortName); } /* The public "getter" to retrieve the chosen port by name. */ public String getSelectedName() { return selectedPortName; } /* The public "getter" to retrieve the selection by CommPortIdentifier. */ public CommPortIdentifier getSelectedIdentifier() { return selectedPortIdentifier; } /** A test program to show up this chooser. */ public static void main(String[] ap) { PortChooser c = new PortChooser(null); c.setVisible(true); // blocking wait System.out.println("You chose " + c.getSelectedName() + " (known by " + c.getSelectedIdentifier() + ")."); System.exit(0); } /** Construct a PortChooser --make the GUI and populate the ComboBoxes. */ public PortChooser(JFrame parent) { super(parent, "Port Chooser", true); makeGUI(); populate(); finishGUI(); } /** Build the GUI. You can ignore this for now if you have not * yet worked through the GUI chapter. Your mileage may vary. */ protected void makeGUI() { Container cp = getContentPane(); JPanel centerPanel = new JPanel(); cp.add(BorderLayout.CENTER, centerPanel); centerPanel.setLayout(new GridLayout(0,2, PAD, PAD)); centerPanel.add(new JLabel("Serial Ports", JLabel.RIGHT)); serialPortsChoice = new JComboBox(); centerPanel.add(serialPortsChoice); serialPortsChoice.setEnabled(false); centerPanel.add(new JLabel("Parallel Ports", JLabel.RIGHT)); parallelPortsChoice = new JComboBox(); centerPanel.add(parallelPortsChoice); parallelPortsChoice.setEnabled(false); centerPanel.add(new JLabel("Unknown Ports", JLabel.RIGHT)); other = new JComboBox(); centerPanel.add(other); other.setEnabled(false); centerPanel.add(new JLabel("Your choice:", JLabel.RIGHT)); centerPanel.add(choice = new JLabel()); JButton okButton; cp.add(BorderLayout.SOUTH, okButton = new JButton("OK")); okButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { PortChooser.this.dispose(); } }); } /** Populate the ComboBoxes by asking the Java Communications API * what ports it has. Since the initial information comes from * a Properties file, it may not exactly reflect your hardware. */ protected void populate() { // get list of ports available on this particular computer, // by calling static method in CommPortIdentifier. Enumeration pList = CommPortIdentifier.getPortIdentifiers(); // Process the list, putting serial and parallel into ComboBoxes while (pList.hasMoreElements()) { CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement(); // System.out.println("Port " + cpi.getName()); map.put(cpi.getName(), cpi); if (cpi.getPortType() == CommPortIdentifier.PORT_SERIAL) { serialPortsChoice.setEnabled(true); serialPortsChoice.addItem(cpi.getName()); } else if (cpi.getPortType() == CommPortIdentifier.PORT_PARALLEL) { parallelPortsChoice.setEnabled(true); parallelPortsChoice.addItem(cpi.getName()); } else { other.setEnabled(true); other.addItem(cpi.getName()); } } serialPortsChoice.setSelectedIndex(-1); parallelPortsChoice.setSelectedIndex(-1); } protected void finishGUI() { serialPortsChoice.addItemListener(this); parallelPortsChoice.addItemListener(this); other.addItemListener(this); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
}
</source>