#include /* * 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 * * {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; iio_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; }