FileDocCategorySizeDatePackage
JMModel.javaAPI DocExample9040Sun Apr 11 19:50:40 BST 2004None

JMModel

public class JMModel extends Object
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 $

Fields Summary
JModem
theGUI
The View
private javax.comm.SerialPort
thePort
The javax.com.CommPort object in use
private InputStream
serialInput
The input and output streams
private OutputStream
serialOutput
protected static final int
BUFSIZE
The size of the static read buffer.
static byte[]
buf
A buffer for the read listener; preallocated once.
protected Thread
serialReadThread
A Thread for reading from the remote.
protected TModem
xferProg
A file transfer program
static int
S_DISCONNECTED
The state for disconnected and connected
static int
S_CONNECTED
int
state
The state, either disconnected or connected
static int
S_INTERACT
The substate settings
static int
S_XFER
int
submode
The online state, either interactive or in xfer. Used by the main reader thread to avoid reading data meant for the xfer program.
public static final int
PARITY_NONE
public static final int
PARITY_EVEN
public static final int
PARITY_ODD
private int[]
baudot
private String[]
sysTypes
protected HashMap
portsIDmap
protected String
DEFAULT_LOG_FILE
Constructors Summary
public JMModel(JModem gui)
Constructor


	  
	   
		theGUI = gui;
	
Methods Summary
voidconnect()
Connect to the chosen serial port, and set parameters.


		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();
	
public voiddelay(long milliseconds)
Convenience routine, due to useless InterruptedException

		try {
			Thread.sleep(milliseconds);
		} catch (InterruptedException e) {
			// can't happen
		}
	
voiddisconnect()
Break our connection to the serial port.

		// 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();
	
voidpopulateComboBox()
Load the list of Serial Ports into the chooser. This code is far too chummy with the innards of class JModem.

		// 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);
			}
		}
	
public voidsaveLogFile()
Use normal java.io to save the JTextArea's session log into a file.


	            	 	
	   
		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);
	
voidsendChar(char ch)
Send one character to the remote

		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();
		}
	
private voidsendString(java.lang.String s)
Send a String of characters to the remote.

		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();
		}
	
public voidxfer()
Do one complete file transfer, using TModem


		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 (ProtocolBotchException ev) {
			theGUI.err("Protocol failure:\n" + ev);
			return;
		} finally {
			submode = S_INTERACT;
		}
		theGUI.note("File Transfer completed");