FileDocCategorySizeDatePackage
TModem.javaAPI DocExample7420Sun Apr 11 19:50:40 BST 2004None

TModem

public class TModem extends Object
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.com/ $Id: TModem.java,v 1.10 2004/04/11 23:50:40 ian Exp $

Fields Summary
protected final byte
CPMEOF
protected final int
MAXERRORS
protected final int
SECSIZE
protected final int
SENTIMOUT
protected final int
SLEEP
protected final byte
SOH
protected final byte
EOT
protected final byte
ACK
protected final byte
NAK
protected InputStream
inStream
protected OutputStream
outStream
protected PrintWriter
errStream
protected boolean
standalone
If we're in a standalone app it is OK to System.exit()
protected boolean
gotChar
A flag used to communicate with inner class IOTimer
Constructors Summary
public TModem(InputStream is, OutputStream os, PrintWriter errs)
Construct a TModem


	    
	       
		inStream = is;
		outStream = os;
		errStream = errs;
	
public TModem()
Construct a TModem with default files (stdin and stdout).

		inStream = System.in;
		outStream = System.out;
		errStream = new PrintWriter(System.err);
	
Methods Summary
protected voiddie(int how)

		if (standalone)
			System.exit(how);
		else throw new ProtocolBotchException("Error code " + how);
	
protected bytegetchar()

		return (byte)inStream.read();
	
public booleanisStandalone()

		return standalone;
	
public static voidmain(java.lang.String[] argv)
A main program, for direct invocation.


		/* 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);
	
protected voidputchar(int c)

		outStream.write(c);
	
public booleanreceive(java.lang.String tfile)

		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;
	
public booleansend(java.lang.String tfile)

		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;
	
public voidsetStandalone(boolean is)

	    
		standalone = is;
	
protected static voidusage()

		System.err.println("usage: TModem -r/-s file");
		// not errStream, not die(), since this is static.
		System.exit(1);
	
protected voidxerror()

		errStream.println("too many errors...aborting");
		die(1);