JModem -简单的通信程序 : 调制解调器 « 网络协议 « Java

En
Java
1. 图形用户界面
2. 三维图形动画
3. 高级图形
4. 蚂蚁编译
5. Apache类库
6. 统计图
7. 
8. 集合数据结构
9. 数据类型
10. 数据库JDBC
11. 设计模式
12. 开发相关类
13. EJB3
14. 电子邮件
15. 事件
16. 文件输入输出
17. 游戏
18. 泛型
19. GWT
20. Hibernate
21. 本地化
22. J2EE平台
23. 基于J2ME
24. JDK-6
25. JNDI的LDAP
26. JPA
27. JSP技术
28. JSTL
29. 语言基础知识
30. 网络协议
31. PDF格式RTF格式
32. 映射
33. 常规表达式
34. 脚本
35. 安全
36. Servlets
37. Spring
38. Swing组件
39. 图形用户界面
40. SWT-JFace-Eclipse
41. 线程
42. 应用程序
43. Velocity
44. Web服务SOA
45. 可扩展标记语言
Java 教程
Java » 网络协议 » 调制解调器屏幕截图 
JModem -简单的通信程序

/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 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.comm.CommPortIdentifier;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.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.com/
 @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 = 9600192003840057600115200 };
  /** 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(5050));
      databitsPanel.setMinimumSize (new java.awt.Dimension(00));
      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(5050));
      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(10020));
      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.com/");
  }//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(2080);
    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.com/
 @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.com.CommPort 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 = 9600192003840057600115200 };
  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() == ?
        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.comm 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.com
 * $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[] argvthrows 
        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 tfilethrows 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 tfilethrows 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 cthrows 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));
    }
}


           
       
Related examples in the same category
1. A tiny version of Ward Christensen's MODEM program for UNIX
2. Subclasses CommPortOpen and adds send/expect handling for dealing with Hayes-type modems
3. 打印到使用Java串行端口通信
www.java2java.com | Contact Us
Copyright 2010 - 2030 Java Source and Support. All rights reserved.
All other trademarks are property of their respective owners.