home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
modems
/
modem2
/
rt11modm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1985-07-20
|
8KB
|
353 lines
#include <stdio.h>
/*
* rtmodem.c -- This program allows the RT-11 user to transfer files to
* and from a host system (usually CP/M) using Ward Christensen's
* MODEM/XMODEM protocol. No terminal emulation is provided (yet).
* Written in DECUS C by:
*
* Robert B. Hoffman, N3CVL 5-Mar-82
* <Hoffman%Pitt.csnet@CSNet-Relay.ARPA>
* {allegra, bellcore, cadre, idis, psuvax1}!pitt!hoffman
*
* 5-Mar-82 Original Version
*
* 18-Mar-83 Changed transmit routine to wait for one of (ACK,NAK,CAN,
* or TIMEOUT) before re-sending the sector. Garbage chars are
* now ignored. Changed receive routine to print a count of
* bytes transferred.
*
* 26-Aug-83 Changed transmit routine to print a count of bytes
* transferred. Changed receive routine to cancel transfer if
* the allocated file size is exceeded. *** Note: This is
* bogus -- putc() isn't returning any error condition. (see below)
*
* 9-Dec-83 Changed receive routine to send NAKs only after it times
* out waiting for a SOH, rather than NAKing every non-SOH.
*
* 13-Feb-84 Changed buffer array from char to ints. It seems that when
* putc was called with a char with the eighth bit set, then
* it was returning a negative int, which appeared as an error.
* If putc is called with an int, it works just fine, and returns
* the expected error condition not found above. Also changed
* command structure to make it quicker. Now, when a transfer
* completes, it returns to command mode rather than exiting.
*
* 19-Feb-84 Changed the 'bytes transmitted' message to indicate sectors,
* blocks, and bytes. Added bell chars to termination messages.
*
* 15-Aug-84 Fixed a bug that allowed nulls to be transmitted in text mode
* and appended an extra sector's worth of nulls in binary mode.
* Also changed command scanner to add Ethernet escape option
* and to make it easier to add more options. Added Ethernet
* escapes to output driver.
*/
struct device {
int rcsr;
int rbuf;
int xcsr;
int xbuf;
};
#define SOH 01
#define EOT 04
#define ACK 06
#define NAK 025
#define CAN 030
#define TIMEOUT -1
#define TRUE 1
#define FALSE 0
#define EVER ;;
int $$narg = 1;
struct device *dladdr = 0176500;
int buf[128];
int ether;
FILE *file;
main() {
register int i, c;
register char *p;
char blkno, cblkno, *filnam, cmdlin[40];
int bcnt, cksm, ok, nakcount, sndrcv, txtbin;
long nbytes;
printf("RTMODEM -- RT-11 file transfer program\n\n");
cmd:
do {
printf("RTMODEM command=> ");
gets(cmdlin);
for (i=0; i<strlen(cmdlin); i++)
cmdlin[i] = (isupper(cmdlin[i]) ? tolower(cmdlin[i]) : cmdlin[i]);
filnam = index(cmdlin,' ');
*filnam++ = 0; /* this is sneaky -- it null-terminates the */
/* command part of the string and makes */
/* filnam point to the file name */
ok = TRUE; /* assume cmd will be OK */
p = index(cmdlin,'s'); /* sending */
if (p == NULL) {
p = index(cmdlin,'r'); /* receiving */
}
if (p == NULL) {
ok = FALSE; /* one of these MUST be present */
}
sndrcv = *p;
p = index(cmdlin,'t'); /* text */
if (p == NULL) {
p = index(cmdlin,'b'); /* binary */
}
if (p == NULL) {
ok = FALSE; /* one of these must also be present */
}
txtbin = *p;
if (index(cmdlin,'e') == NULL) { /* ethernet mode */
ether = FALSE;
} else {
ether = TRUE;
}
if (!ok) {
printf("\nCommands are of the form:\n");
printf(" rt|rb|st|sb [e] filename\n");
printf(" rt -- receive text\n");
printf(" rb -- receive binary\n");
printf(" st -- send text\n");
printf(" sb -- send binary\n");
printf(" e -- use Ethernet escape\n\n");
}
} while (!ok);
freopen("tt:", "wu", stdout);
if (ether) {
printf("Using Ethernet character escape.\n");
}
if (sndrcv == 's') {
printf("Sending file %s, %s mode.\n", filnam,
(txtbin == 't' ? "text" : "binary"));
if ((file = fopen(filnam,"rn")) == NULL) {
fprintf(stderr,"Couldn't open input file %s.\n",
filnam);
goto cmd;
}
printf("File open, ready to send.\n");
nbytes = 512L * (long)(file->io_size);
printf("File is %d sectors (%ld bytes) long.\n",
(file->io_size) * 4, nbytes);
nbytes /= 84L; /* 120 cps * 70% = 84 cps effective */
printf("Estimated transfer time: %ld min, %ld sec at 1200 bps.\n",
nbytes/60L, nbytes%60L);
while ((c = getmod()) != NAK)
;
nbytes = 0L;
blkno = 0;
do {
i = 0;
do {
c = getc(file);
if (c == EOF) {
if (i == 0)
goto sfin;
if (txtbin == 't')
buf[i++] = 032;
else
buf[i++] = 0;
}
else if (txtbin != 't' || c != 0) {
buf[i++] = c;
}
} while (i < 128);
blkno++;
do {
outmod(SOH);
outmod(blkno);
outmod(~blkno);
cksm = 0;
for (bcnt = 0; bcnt < 128; bcnt++) {
outmod(buf[bcnt]);
cksm = (cksm + buf[bcnt]) % 256;
}
outmod(cksm);
do {
ok = TRUE; /* Assume all OK */
c = getmod();
switch (c) {
case ACK:
case NAK:
case CAN:
case TIMEOUT:
break;
default:
ok = FALSE;
break;
}
} while (!ok);
} while (c != ACK && c != CAN);
nbytes += 128L;
printf("%ld sec, %ld blk, %ld b\r", nbytes/128L,
(nbytes+384L)/512L, nbytes);
if (c == CAN) {
fclose(file);
printf("\n\007\007\007Transfer cancelled by host.\n");
goto cmd;
}
} while (c == ACK && !feof(file));
sfin:
outmod(EOT);
c = getmod();
if (c == ACK)
printf("\n\007\007\007File transmitted\n");
else
printf("\n\007\007\007Final ACK was 0%o instead!\n",c);
fclose(file);
goto cmd;
}
else {
printf("Receiving file %s, %s mode.\n", filnam,
(txtbin == 't' ? "text" : "binary"));
if ((file = fopen(filnam,"wn")) == NULL) {
fprintf(stderr,"Couldn't open output file %s\n",
filnam);
goto cmd;
}
printf("File open, ready to receive.\n");
nbytes = 0L;
outmod(NAK); /* Send initial NAK */
nakcount = 0;
for (EVER) {
do {
c = getmod();
switch (c) {
case TIMEOUT:
outmod(NAK);
nakcount++;
break;
case EOT:
goto rfin;
default:
break;
}
} while (c != SOH);
blkno = getmod();
cblkno = getmod();
cksm = 0;
for (i=0; i<128; i++) {
c = buf[i] = getmod();
cksm = (cksm + c) % 256;
}
c = getmod();
ok = (((SOH+blkno+cblkno) % 256) == 0 && cksm == c);
if (ok) {
for (i=0; i<128; i++) {
if (buf[i] == '\032' && txtbin == 't')
break;
c = putc(buf[i],file);
if (c == EOF) {
outmod(CAN);
fclose(file);
printf("\n\07Disk full! Transfer cancelled.\n");
goto cmd;
}
}
nbytes += 128L;
printf("%ld sec, %ld blk, %ld b\r",
nbytes/128L, (nbytes+384L)/512L,
nbytes);
outmod(ACK);
nakcount = 0;
} else {
if (nakcount > 10) {
printf("\nR)etry or Q)uit=> ");
gets(cmdlin);
c = cmdlin[0];
if (c == 'q' || c == 'Q') {
outmod(CAN);
fclose(file);
goto cmd;
}
nakcount = 0;
}
nakcount++;
printf("\nNAK %d\n", nakcount);
outmod(NAK);
}
}
rfin:
fclose(file);
outmod(ACK);
printf("\n\007\007\007Transfer complete\n");
goto cmd;
}
}
/*
* get a character from the modem. A 10 second timeout is
* needed to preclude hanging the modem if one side should
* terminate abnormally. The constant of 160000 provides this
* delay for an LSI-11.
*/
getmod() {
register struct device *MODEM;
long n;
MODEM = dladdr;
for (n=160000L; ((MODEM->rcsr & 0200) == 0) && (n > 0L); n--)
;
if (n == 0L) {
printf("\nTimeout!\n");
return(-1);
}
return((MODEM->rbuf) & 0377);
}
/*
* Send a character to the modem.
*/
outmod(c)
char c;
{
if (ether) {
switch(c) {
case 020:
case 021:
case 023:
outm(020);
break;
default:
break;
}
}
outm(c);
}
outm(c)
char c;
{
register struct device *MODEM;
MODEM = dladdr;
while ((MODEM->xcsr & 0200) == 0)
;
MODEM->xbuf = c;
}